package com.wander.rep;

import static com.wander.rep.server.CommonUtilities.DEFAULT_SERVER_URL;
import static com.wander.rep.server.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static com.wander.rep.server.CommonUtilities.EXTRA_MESSAGE;
import static com.wander.rep.server.CommonUtilities.SENDER_ID;

import java.util.LinkedList;
import java.util.List;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.SpinnerAdapter;
import android.widget.Toast;

import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.google.android.gcm.GCMRegistrar;
import com.wander.rep.db4o.SingletonHelper;
import com.wander.rep.patient.Patient;
import com.wander.rep.server.ServerUtilities;
import com.wander.rep.service.UpdateService;

/**
 * An activity representing a list of Details. This activity has different
 * presentations for handset and tablet-size devices. On handsets, the activity
 * presents a list of items, which when touched, lead to a
 * {@link DetailActivity} representing item details. On tablets, the
 * activity presents the list of items and item details side-by-side using two
 * vertical panes.
 * <p>
 * The activity makes heavy use of fragments. The list of items is a
 * {@link DetailListFragment} and the item details (if present) is a
 * {@link DetailFragment}.
 * <p>
 * This activity also implements the required
 * {@link DetailListFragment.Callbacks} interface to listen for item selections.
 */
public class DetailListActivity extends FragmentActivity implements
DetailListFragment.Callbacks {

	AsyncTask<Void, Void, Void> mRegisterTask;

	/**
	 * Whether or not the activity is in two-pane mode, i.e. running on a tablet
	 * device.
	 */
	private boolean mTwoPane;

	private Patient currentPatient;

	private ObjectContainer db;

	private final String TAG = "DetailListActivity";

	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
		
		setContentView(R.layout.activity_detail_list);
		
		Log.i(TAG, "Starting DetailListActivity");
		
		startDb4oSession();
		
		loadPatientfromDB();
		
		startService();

		SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list, R.layout.spinner_dropdown);

		ActionBar actionBar = getActionBar();
		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

		OnNavigationListener mNavigationCallback = new OnNavigationListener() 
		{
			@Override
			public boolean onNavigationItemSelected(int position, long itemId) 
			{
				return true;
			}
		};

		actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);

		checkNotNull(DEFAULT_SERVER_URL, "SERVER_URL");
		checkNotNull(SENDER_ID, "SENDER_ID");
		
		Log.i(TAG, "CheckNotNull Passed");

		// Make sure the device has the proper dependencies.
		GCMRegistrar.checkDevice(this);
		Log.i(TAG, "Dependencies Passed");
		// Make sure the manifest was properly set - comment out this line
		// while developing the app, then uncomment it when it's ready.
		GCMRegistrar.checkManifest(this);
		Log.i(TAG, "Manifest Passed");

		registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
		Log.i(TAG, "Receiver Registered");

		final String regId = GCMRegistrar.getRegistrationId(this);

		if (regId.equals("")) {
			// Automatically registers application on startup.
			Log.i(TAG, "Registering Application with GCM Server");
			GCMRegistrar.register(this, SENDER_ID);

		} else {
			// Device is already registered on GCM, check server.
			if (GCMRegistrar.isRegisteredOnServer(this)) {
				// Skips registration.
				Log.i(TAG, "Registration skipped: Already Registered");
			} else {
				// Try to register again, but not in the UI thread.
				// It's also necessary to cancel the thread onDestroy(),
				// hence the use of AsyncTask instead of a raw thread.
				Log.i(TAG, "Trying to register again.");
				final Context context = this;
				mRegisterTask = new AsyncTask<Void, Void, Void>() {

					/*
					 * (non-Javadoc)
					 * @see android.os.AsyncTask#doInBackground(Params[])
					 */
					@Override
					protected Void doInBackground(Void... params) {
						boolean registered = ServerUtilities.register(context, regId, getUsername(), getEmailAddress());
						// At this point all attempts to register with the app
						// server failed, so we need to unregister the device
						// from GCM - the app will try to register again when
						// it is restarted. Note that GCM will send an
						// unregistered callback upon completion, but
						// GCMIntentService.onUnregistered() will ignore it.
						if (!registered) 
						{
							GCMRegistrar.unregister(context);
						}
						return null;
					}

					@Override
					protected void onPostExecute(Void result) {
						mRegisterTask = null;
					}

				};
				mRegisterTask.execute(null, null, null);
			}
		}

		if (findViewById(R.id.detail_detail_container) != null) {
			
			 /* The detail container view will only be available
			 in large screen layouts (loaded from res/values-large and
			 res/values-sw600dp). If the view is available, the
			 activity should be in two-pane mode. */ 
			mTwoPane = true;
			Log.e(TAG, "Setting Two Pane");

			/* In two-pane mode, list items should be given the
			  'activated' state when touched since they will be
			  represented in the left pane. */
			((DetailListFragment) getSupportFragmentManager().findFragmentById(
					R.id.detail_list)).setActivateOnItemClick(true);
		}
	}

/*	private void unregisterIntent() {
		
		Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
		unregIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0));
		startService(unregIntent);
		
	}*/

	/*
	 * Starts Databasae Session from SQLite Helper
	 */
	private void startDb4oSession() {
		
		db = SingletonHelper.getInstance(getApplicationContext()).getDatabaseSession();
		
	}

	/*
	 * Starts the Update Service
	 */
	private void startService() {
		
		Intent serviceIntent = new Intent(this, UpdateService.class);
		this.startService(serviceIntent);
		
	}

	/*
	 * Loads Patients from Database
	 */
	protected boolean loadPatientfromDB() {

		ObjectSet<Patient> patients = db.query(Patient.class);

		if(!patients.isEmpty())
		{
			setCurrentPatient(patients.get(0));
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * Callback method from {@link DetailListFragment.Callbacks} indicating that
	 * the item with the given ID was selected.
	 */
	@Override
	public void onItemSelected(String id) {
		if (mTwoPane) {
			// In two-pane mode, show the detail view in this activity by
			// adding or replacing the detail fragment using a
			// fragment transaction.
			Bundle arguments = new Bundle();
			arguments.putString(DetailFragment.ARG_ITEM_ID, id);

			DetailFragment fragment = new DetailFragment();
			fragment.setArguments(arguments);
			getSupportFragmentManager().beginTransaction()
			.replace(R.id.detail_detail_container, fragment).commit();

		} else {
			// In single-pane mode, simply start the detail activity
			// for the selected item ID.
			Intent detailIntent = new Intent(this, DetailActivity.class);
			detailIntent.putExtra(DetailFragment.ARG_ITEM_ID, id);
			startActivity(detailIntent);
		}
	}

	/*
	 * Checks if a String is null, throwing NullPointerException if true
	 */
	private void checkNotNull(Object reference, String name) {
		if (reference == null) {
			Log.e(TAG,  getString(R.string.error_config, name));

			throw new NullPointerException(
					getString(R.string.error_config, name));
		}
	}

	/*
	 * Listens to BroadcastReceiver for GCM Messages
	 */
	private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
			Log.i(TAG, "Received Msg from GCM: " + newMessage);
		}
	};

	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.FragmentActivity#onDestroy()
	 */
	@Override
	protected void onDestroy() {
		if (mRegisterTask != null) {
			mRegisterTask.cancel(true);
		}
		unregisterReceiver(mHandleMessageReceiver);
		
		if(db != null)
		{
			db.close();
			SingletonHelper.getInstance(getApplicationContext()).close();
		}
		
		GCMRegistrar.onDestroy(this);
		super.onDestroy();
	}

	/*
	 * Queries user's Google Account for Username
	 */
	public String getUsername(){
		AccountManager manager = AccountManager.get(this); 
		Account[] accounts = manager.getAccountsByType("com.google"); 
		List<String> possibleEmails = new LinkedList<String>();

		for (Account account : accounts) {
			// TODO: Check possibleEmail against an email regex or treat
			// account.name as an email address only for certain account.type values.
			possibleEmails.add(account.name);
		}

		if(!possibleEmails.isEmpty() && possibleEmails.get(0) != null){
			String email = possibleEmails.get(0);
			String[] parts = email.split("@");
			if(parts.length > 0 && parts[0] != null)
				return parts[0];
			else
				return null;
		}else
			return null;
	}

	/*
	 * Queries user's Google Account for e-mail Address
	 */
	public String getEmailAddress(){
		AccountManager manager = AccountManager.get(this); 
		Account[] accounts = manager.getAccountsByType("com.google"); 
		List<String> possibleEmails = new LinkedList<String>();

		for (Account account : accounts) {
			// TODO: Check possibleEmail against an email regex or treat
			// account.name as an email address only for certain account.type values.
			possibleEmails.add(account.name);
		}

		if(!possibleEmails.isEmpty() && possibleEmails.get(0) != null)
		{
			String email = possibleEmails.get(0);
			return email;
		}
		else
		{
			return null;
		}
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_activity, menu);
		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch(item.getItemId())
		{
		case R.id.item1 :
			AddPatientDialog apd = new AddPatientDialog();
			apd.show(getSupportFragmentManager(), "AddPatientDialog");
			break;
		case R.id.item2 :
			Intent settingsActivity = new Intent(this.getApplicationContext(), SettingsActivity.class);
			startActivity(settingsActivity);
			break;
		case R.id.item3 :
			break;
		case R.id.item4 :
			if(!isUpdateServiceRunning())
			{
				startService();
				loadPatientfromDB();
			}
			else
			{
				Toast.makeText(getApplicationContext(), "Update already in progress", Toast.LENGTH_LONG).show();
			}
			break;
		default :
			return super.onOptionsItemSelected(item);
		}
		return false;
	}
	
	/*
	 * Returns true if UpdateService is running, false if not
	 */
	private boolean isUpdateServiceRunning() 
	{
	    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
	    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
	        if (UpdateService.class.getName().equals(service.service.getClassName())) {
	            return true;
	        }
	    }
	    return false;
	}
	
	/*
	 * Returns true if user is connected to the internet
	 */
	public boolean isConnectingToInternet(){
        ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
          if (connectivity != null)
          {
              NetworkInfo[] info = connectivity.getAllNetworkInfo();
              if (info != null)
                  for (int i = 0; i < info.length; i++)
                      if (info[i].getState() == NetworkInfo.State.CONNECTED)
                      {
                          return true;
                      }
 
          }
          return false;
    }

	/*
	 * Setter for currentPatient
	 */
	public void setCurrentPatient(Patient currentPatient) {
		
		this.currentPatient = currentPatient;
	
	}
	
	/*
	 * Getter for currentPatient
	 */
	public Patient getCurrentPatient() {
		
		return this.currentPatient;
		
	}
}
